import { parseTime } from './ruoyi'

/**
 * 表格时间格式化
 */
export function formatDate(cellValue) {
  if (cellValue == null || cellValue == "") return "";
  var date = new Date(cellValue) 
  var year = date.getFullYear()
  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() 
  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() 
  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 
  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i)
    if (code > 0x7f && code <= 0x7ff) s++
    else if (code > 0x7ff && code <= 0xffff) s += 2
    if (code >= 0xDC00 && code <= 0xDFFF) i--
  }
  return s
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = []
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i])
    }
  }
  return newArray
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return ''
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) return ''
      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
    })
  ).join('&')
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  if (!search) {
    return {}
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
    }
  })
  return obj
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement('div')
  div.innerHTML = val
  return div.textContent || div.innerText
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  if (nameIndex === -1) {
    classString += '' + className
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length)
  }
  element.className = classString
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  } else {
    return new Date(new Date().toDateString())
  }
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + ''
  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
  return (+(randomNum + timestamp)).toString(32)
}

/**
 * 得到两个时间的秒数
 * @param {*} start 
 * @param {*} end 
 */
export function getTimeSeconds(start, end) {
  let startSecs = start.getTime();
  let endSecs = end.getTime();
  // console.log('startSecs=', startSecs , '; endSecs=', endSecs, '=', endSecs - startSecs);
  let secs = (endSecs - startSecs) / 1000;
  return secs;
}

/**
 * 得到文件固定信息(类型；路径)
 * @param {*} params 
 */
export function getFileFixedInfo(fileName) {
  let imgExts = ["png", "jpg", "jpeg"];
  let excelExts = ['xls', 'xlsx'];
  let docExts = ['doc', 'docx'];
  let names = fileName ? fileName.split('.') : [];
  let ext = names.at(-1); // 文件扩展名
  let path = undefined;
  let type = undefined;
  if (imgExts.indexOf(ext.toLowerCase()) !== -1) {
    // path = require('../../../assets/images/image.png');
    path = require('../assets/images/image.png')
    type = 'png';
  } else if (excelExts.indexOf(ext.toLowerCase()) !== -1) {
    path = require('../assets/images/excel.png');
    type = 'xls';
  } else if (docExts.indexOf(ext.toLowerCase()) !== -1) {
    path = require('../assets/images/doc.png');
    type = 'doc';
  } else if (ext.toLowerCase() == 'pdf') {
    path = require('../assets/images/pdf.png');
    type = 'pdf';
  }
  return {type: type, path: path};
}

/**
 * 得到文件url地址
 * @param {*} id 
 * @returns 
 */
export function getFileUrl(id) {
  let url = process.env.VUE_APP_BASE_API + '/obs/download?id=' + id;
  return url;
}
// let url = process.env.VUE_APP_BASE_API + '/obs/download?id=' + ent.id;

/**
 * 保留两位小数
 * @param {*} value 
 */
export function keepTwoDecimal(value, place = 2) {
  if (value === undefined || value === null || value === '') {
    return '';
  }
  let val = undefined;
  if (typeof value == 'number') {
    val = value;
  } else {
    val = Number(value);
  }
  let tmp = 100;
  if (place == 3) {
    tmp = 1000;
  } else if (place == 4) {
    tmp = 1000;
  }
  return (Math.round(val * tmp) / tmp).toFixed(place);
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}

/**
 * 格式化下，把undefined、null 转成 ’‘
 * @param {*} value 
 * @returns 
 */
export function formatString(value) {
  if (value === undefined || value === null) {
    value = '';
  }
  return value;
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls
}

/**
 * 生成随机数
 * @param {*} randomLength 
 * @returns 
 */
export function getUuiD(randomLength) {
  return Number(Math.random().toString().substring(2,randomLength) + Date.now()).toString(36);
}

/**
 * 金额改成 逗号的形式
 * 10000 => "10,000"
 * @param {number} num
 */
export function toThousandFilter(num, place = 2) {
  // console.log('num=', num);
  let money = (+num || 0).toString().replace(/^-?\d+/g, m=>m.replace(/(?=(?!\b)(\d{3})+$)/g, ','));
  // console.log('money=', money);
  let list = money.split('.');
  if (list.length == 1) {
    if (place == 3) {
      return money + '.000';
    } else if (place == 4) {
      return money + '.0000';
    }
    return money + '.00';
  } else if (list.length == 2 && list[1].length == 1) { // 小数点后有一位
    if (place == 3) {
      return money + '00';
    } else if (place == 4) {
      return money + '000';
    }
    return money + '0';
  } else if (list.length == 2 && list[1].length == 2) { // 小数点后有二位
    if (place == 3) {
      return money + '0';
    } else if (place == 4) {
      return money + '00';
    }
    return money + '';
  } else if (list.length == 2 && list[1].length == 3) { // 小数点后有三位
    if (place == 3) {
      return money + '';
    } else if (place == 4) {
      return money + '0';
    }
    return money + '';
  }
  return money;
  // return (+num || 0).toString().replace(/^-?\d+/g, m=>m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
    ele.className = ele.className.replace(reg, ' ')
  }
}

export function makeMap(str, expectsLowerCase) {
  const map = Object.create(null)
  const list = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
}
 
export const exportDefault = 'export default '

export const beautifierConf = {
  html: {
    indent_size: '2',
    indent_char: ' ',
    max_preserve_newlines: '-1',
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: 'separate',
    brace_style: 'end-expand',
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: false,
    end_with_newline: true,
    wrap_line_length: '110',
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true
  },
  js: {
    indent_size: '2',
    indent_char: ' ',
    max_preserve_newlines: '-1',
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: 'normal',
    brace_style: 'end-expand',
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: true,
    end_with_newline: true,
    wrap_line_length: '110',
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true
  }
}

// 首字母大小
export function titleCase(str) {
  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}

// 下划转驼峰
export function camelCase(str) {
  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}

export function isNumberStr(str) {
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}

/**
 * 金额改成 逗号的形式
 * 10000 => "10,000"
 * @param {number} num
 */
// export function toThousandFilter(num) {
//   let money = (+num || 0).toString().replace(/^-?\d+/g, m=>m.replace(/(?=(?!\b)(\d{3})+$)/g, ','));
//   let list = money.split('.');
//   if (list.length == 1) {
//     return money + '.00';
//   } else if (list.length == 2 && list[1].length == 1) {
//     return money + '0';
//   }
//   return money;
// }
 
/**
 * 判断用户使用的设备是否是移动设备
 * @param {*} params 
 */
export function mobileDevice(params = {}) {
  let sUserAgent = navigator.userAgent.toLowerCase();
	let bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
	let bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
	let bIsMidp = sUserAgent.match(/midp/i) == "midp";
	let bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
	let bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
	let bIsAndroid = sUserAgent.match(/android/i) == "android";
	let bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
	let bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
	if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
		// alert('移动端设备');
    return true;
	} else {
		// alert('pc端设备');
    return false;
	}
}

/**
 * table合并行通用
 * @param {*} config
 * @returns
 */
export function mergeTableRow(config) {
  let data = config.data;
  const {
    mergeColNames, // 需要合并的列
    firstMergeColNames, // 受影响的列
    firstMerge, // 以哪列为基础进行合并(基准列)
  } = config;
  if (!mergeColNames || mergeColNames.length === 0) {
    return data;
  }
  mergeColNames.forEach((m) => {
    const mList = {};
    data = data.map((v, index) => {
      // 区分需要合并行的key值
      const rowVal = v[firstMerge] + "-" + v[m];
      // 需要合并行的第二行以及之后行会走if
      // m === firstMerge 判断需要合并的列是否是基准列，如果是则只满足前面的条件，如果不是则需满足前面+后面的条件
      if (
        mList[rowVal] &&
        mList[rowVal].newIndex === index &&
        (m === firstMerge
          ? true
          : data[index][firstMerge + "-span"].rowspan === 0)
      ) {
        // 判断受影响的列是否是需要合并的列
        const flag =
          firstMergeColNames.filter((f) => {
            return f === m;
          }).length !== 0;
        // 判断需要合并的列是否是基准列
        const mcFlag =
          mergeColNames.filter((mc) => {
            return mc === firstMerge;
          }).length === 0;
        // 判断基准列只有一行的时候，直接赋值rowspan和colspan为1
        if (
          (mcFlag && flag) ||
          (flag &&
            data[index][firstMerge + "-span"] &&
            data[index][firstMerge + "-span"].rowspan === 1)
        ) {
          v[m + "-span"] = {
            rowspan: 1,
            colspan: 1,
          };
        } else {
          // 判断基准列或其他需要合并列有多行时，第一行rowspan++
          data[mList[rowVal]["index"]][m + "-span"].rowspan++;
          // 需要合并行除了第一行之后其他行设置rowspan和colspan为0
          v[m + "-span"] = {
            rowspan: 0,
            colspan: 0,
          };
          mList[rowVal]["num"]++;
          mList[rowVal]["newIndex"]++;
        }
      } else {
        // 需要合并列第一行走else
        mList[rowVal] = {
          num: 1,
          index: index,
          newIndex: index + 1,
        };
        v[m + "-span"] = {
          rowspan: 1,
          colspan: 1,
        };
      }
      return v;
    });
  });
  return data;
};

/**数组根据数组对象中的某个属性值进行排序的方法
 * 使用例子：newArray.sort(sortBy('number',false)) //表示根据number属性降序排列;若第二个参数不传递，默认表示升序排序
 * @param attr 排序的属性 如number属性
 * @param rev true表示升序排列，false降序排序
 * */
export function sortBy(attr, rev) {
  //第二个参数没有传递 默认升序排列
  if (rev == undefined) {
    rev = 1;
  } else {
    rev = rev ? 1 : -1;
  }
  return function(a, b) {
    a = a[attr];
    b = b[attr];
    if (a < b) {
      return rev * -1;
    }
    if (a > b) {
      return rev * 1;
    }
    return 0;
  };
}
/**
 * 数组对象去重
 * @param {*} tempArr k 去重标识字段
 * @returns 
 */
 export function uniqueArrObject(tempArr, k) {
  // console.log('tempArr=', tempArr);
  let result = [];
  let obj = {};
  for (let i = 0; i < tempArr.length; i++) {
    const id = tempArr[i][k];
    if (!obj[id]) {
      result.push(tempArr[i]);
      obj[id] = true;
    };
  };
  return result;
};


//根据math.js加减乘除计算封装,参数数字只能number和null类型,当数字超过2^54-1时，可能会出现精度问题
//因为引入chain，即便是按需引入，可能由于chain涉及到的数据方法太多，导致打包时，dist文件直接大了1M左右。
export const calculate = {
  comp: function (_func, args) {
    let t = chain(bignumber(args[0]));
    for (let i = 1; i < args.length; i++) {
      if (typeof args[i] === "number" || typeof args[i] === "null") {
        t = t[_func](bignumber(args[i]));
      }
    }
    // 防止超过6位使用科学计数法
    return parseFloat(t.done());
  },
  //加
  add: function () {
    return this.comp("add", arguments);
  },
  //减
  subtract: function () {
    return this.comp("subtract", arguments);
  },
  //乘
  multiply: function () {
    return this.comp("multiply", arguments);
  },
  //除
  divide: function () {
    return this.comp("divide", arguments);
  },
};
